/* 
 * File:   Post_office.cpp
 * Author: Saulio
 * Created on April 16, 2012, 4:27 PM
 */

#include "Frame.h"

static const int MESSAGE_QUEUE_KEY=76;

int main(int, char**);
int Packer(Header &, message &, std::string &);
class Defined_version_1;

class Fill_out_message
{
protected:
   virtual void Fill_out_investment (char&, char&, unsigned int&, unsigned int&, char**)=0;
   virtual void Fill_out_guards (unsigned short&, unsigned short&, unsigned short&, char**, 
                                 unsigned int&, unsigned int&, char**)=0;
   virtual void Fill_out_missing_report(unsigned short&, char**)=0;
   virtual void Fill_out_adoption_papers (unsigned int&, char**, char**)=0;
   
   friend clas  s Defined_version_1;
};

class Defined_version_1 : public Fill_out_message
{

private:
   Fill_out_investment                 (char &version, char &domain, 
                                        unsigned int &id_server_source, 
                                        unsigned int &id_server_destination, 
                                        char** argv)
   {
       version=                         char(atoi(argv[4]));
       domain=                          char(atoi(argv[5]));
       id_server_source=                atoi(id_server_source);
       id_server_destination=           atoi(id_server_destination);
   }
   
   Fill_out_guards                     (unsigned short &family, 
                                        unsigned short &port_source, 
                                        unsigned short &port_destination, 
                                        char** ip_address_client, 
                                        unsigned int &sequence_number, 
                                        unsigned int &acknowledge_number,
                                        char** argv)
   {
        family=                         atoi(argv[8]);
        port_source=                    atoi(argv[9]);
        port_destination=               atoi(argv[10]);
        *ip_address_client=             new char[strlen(argv[11])+1];
                                        strcpy(*ip_address_client, argv[11]);
        sequence_number=                atoi(argv[12]);
        acknowledge_number=             atoi(argv[13]);
   }trigger_id=*argv[2];

   Fill_out_missing_report(unsigned short &tcp_payload, char** argv)
   {
        tcp_payload=                    atoi(argv[14]);
   }

   Fill_out_adoption_papers             (unsigned int &id_server_guardian, 
                                         char** ip_address_guardian, 
                                         char** argv)
   {
        id_server_guardian=              atoi(argv[15]);
        *ip_address_guardian=            new char[strlen(argv[16])+1];
                                         strcpy(*ip_address_guardian, argv[16]);
   }    
   friend int main(int argc, char** argv);
};


int main(int argc, char** argv)
{

    unsigned char               trigger_id;
    char*                       ip_address_destination;
    char                        version;
    char                        domain;
    unsigned int                id_server_source;
    unsigned int                id_server_destination;
    unsigned short              family; 
    unsigned short              port_source;
    unsigned short              port_destination;
    char*                       ip_address_client;
    unsigned int                sequence_number; 
    unsigned int                acknowledge_number;
    unsigned short              tcp_payload;
    unsigned int                id_server_guardian;
    char*                       ip_address_guardian;
    message                     package;
    
    ip_address_destination=new char[strlen(argv[3])+1];
    strcpy(ip_address_destination, argv[3]);
    trigger_id=*argv[2];
    
    switch(trigger_id){
        
        case 65:{
            Defined_version_1.Fill_out_investment(version, domain, id_server_source,
                                                  id_server_destination, argv); 
            
            Header h_i(version, domain, id_server_source, id_server_destination);
            Investment invt(h_i);
            package.date_time=invt.date_time;
            Packer(invt.header, package, ip_address_destination);
            break;
        } 
        case 66:{
             Defined_version_1.Fill_out_investment(version, domain, id_server_source, 
                                                   id_server_destination, argv);
             
             Defined_version_1.Fill_out_guards(family, port_source, port_destination, 
                                               &ip_address_client, sequence_number, 
                                               acknowledge_number, argv);
            
             Header h_g(version, domain, id_server_source, id_server_destination,
                        family, port_source,port_destination, ip_address_client);
          
             Guard g(h_g, sequence_number, acknowledge_number);
             package.id_client=g.id_client;
             package.date_time=g.date_time;
             package.guard=g.guard;
             Packer(g.header, package , ip_address_destination);
             break;
        }
        case 67:{
             Defined_version_1.Fill_out_investment(version, domain, id_server_source, 
                                                   id_server_destination, argv);
            
             Defined_version_1.Fill_out_guards(family, port_source, port_destination, 
                                               &ip_address_client, sequence_number, 
                                               acknowledge_number, argv);
            
             Defined_version_1.Fill_out_missing_report(tcp_payload,argv);
            
             Header h_mr(version, domain, id_server_source, id_server_destination, 
                         family, port_source, port_destination, ip_address_client);
            
             Missing_report mr(h_mr, sequence_number, acknowledge_number, tcp_payload);
             
             package.id_client=mr.id_client;
             package.date_time=mr.date_time;
             package.missing_report=mr.missing_report;
             Packer(mr.header, package , ip_address_destination);
             break;
        }
        case 68:{
             Defined_version_1.Fill_out_investment(version, domain, id_server_source, 
                                                   id_server_destination, argv);
            
             Defined_version_1.Fill_out_guards(family, port_source, port_destination, 
                                               &ip_address_client, sequence_number, 
                                               acknowledge_number, argv);
            
             Defined_version_1.Fill_out_adoption_papers(id_server_guardian, &ip_address_guardian, argv);
            
             Header h_ap(version, domain, id_server_source, id_server_destination, 
                        family, port_source, port_destination, ip_address_client);
            
             Adoption_papers ap(h_ap, id_server_guardian, ip_address_guardian, family);
             
             package.id_client=ap.id_client;
             package.date_time=ap.date_time;
             package.adoption_papers=ap.adoption_papers;
             Packer(ap.header, package , ip_address_destination);
             break;
        }
        default:{ 
            return(EXIT_FAILURE);
            break;
        }
    }
    delete[] ip_address_guardian;
    
    return(EXIT_SUCCESS);
};

int Packer(Header &header, message &package, std::string &ip_address_destination)
{
       
    struct iovec v[2];
    struct msghdr mh;
    struct sockaddr_in serv_addr;
    int sockfd, Quimera_port, n_bytes_write;
    char *ip=new char[ip_address_destination.size()+1];
    
    v[0].iov_base=&header;
    v[0].iov_len=sizeof(header);
    v[1].iov_base=&package;
    v[1].iov_len=sizeof(package);
    
    
    ip[ip_address_destination.size()]=0;
    memcpy(ip,ip_address_destination.c_str(),ip_address_destination.size());  
    Quimera_port = 710;
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_addr.s_addr=inet_addr(ip);
    serv_addr.sin_port = htons(Quimera_port);
   
    mh.msg_name =  &serv_addr;
    mh.msg_namelen = sizeof(serv_addr);
    mh.msg_iov = v;
    mh.msg_iovlen = 2;
      
    n_bytes_write = sendmsg(sockfd, &mh, 0);
    
    close(sockfd);
    
    return (EXIT_SUCCESS);
    
};